namespace ImageProcessing
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;    
    using System.Drawing.Imaging;
    using System.IO;
    using System.Text;
    using System.Windows.Forms;

    /// <summary>
    /// canny class
    /// </summary>
    public class Canny
    {
        /// <summary>
        /// width w heigth image
        /// </summary>
        private int width1, height1;

        /// <summary>
        /// bitmap iamge
        /// </summary>
        private Bitmap obj;

        /// <summary>
        /// grey image
        /// </summary>
        private int[,] greyImage; 

        // Gaussian Kernel Data

        /// <summary>
        /// gaussian Kernel
        /// </summary>
        private int[,] gaussianKernel;

        /// <summary>
        /// kernel Weight
        /// </summary>
        private int kernelWeight;

        /// <summary>
        /// kernel Size
        /// </summary>
        private int kernelSize = 5;

        /// <summary>
        /// sigma for gussian
        /// </summary>
        private float sigma = 1;   

        // Canny Edge Detection Parameters

        /// <summary>
        /// max Hysteresis Thresh, min Hysteresis Thresh;
        /// </summary>
        private float maxHysteresisThresh, minHysteresisThresh;

        /// <summary>
        /// derivative X
        /// </summary>
        private float[,] derivativeX;

        /// <summary>
        /// derivative Y
        /// </summary>
        private float[,] derivativeY;

        /// <summary>
        /// filtered Image
        /// </summary>
        private int[,] filteredImage;

        /// <summary>
        /// gradient image
        /// </summary>
        private float[,] gradient;
            
        /// <summary>
        /// nonmax image
        /// </summary>
        private float[,] nonMax;

        /// <summary>
        /// Post Hysteresis
        /// </summary>
        private int[,] postHysteresis;

        /// <summary>
        /// edge points
        /// </summary>
        private int[,] edgePoints;

        /// <summary>
        /// gnh var
        /// </summary>
        private float[,] gNH;

        /// <summary>
        /// gnl var
        /// </summary>
        private float[,] gNL;

        /// <summary>
        /// edge Map
        /// </summary>
        private int[,] edgeMap;

        /// <summary>
        /// visited Map
        /// </summary>
        private int[,] visitedMap;

        /// <summary>
        /// Initializes a new instance of the <see cref="Canny"/> class.
        /// </summary>
        /// <param name="input">The input.</param>
        public Canny(Bitmap input)
        {
            // Gaussian and Canny Parameters
            this.maxHysteresisThresh = 20F;
            this.minHysteresisThresh = 10F;
            this.obj = input;
            this.width1 = this.obj.Width;
            this.height1 = this.obj.Height;
            this.edgeMap = new int[this.width1, this.height1];
            this.visitedMap = new int[this.width1, this.height1];

            this.ReadImage();
            this.DetectCannyEdges();
            return;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Canny"/> class.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <param name="th">The th.</param>
        /// <param name="tl">The tl.</param>
        public Canny(Bitmap input, float th, float tl)
        {
            // Gaussian and Canny Parameters
            this.maxHysteresisThresh = th;
            this.minHysteresisThresh = tl;

            this.obj = input;
            this.width1 = this.obj.Width;
            this.height1 = this.obj.Height;

            this.edgeMap = new int[this.width1, this.height1];
            this.visitedMap = new int[this.width1, this.height1];

            this.ReadImage();
            this.DetectCannyEdges();
            return;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Canny"/> class.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <param name="th">The th.</param>
        /// <param name="tl">The tl.</param>
        /// <param name="gaussianMaskSize">Size of the gaussian mask.</param>
        /// <param name="sigmaforGaussianKernel">The sigmafor gaussian kernel.</param>
        public Canny(Bitmap input, float th, float tl, int gaussianMaskSize, float sigmaforGaussianKernel)
        {
            // Gaussian and Canny Parameters
            this.maxHysteresisThresh = th;
            this.minHysteresisThresh = tl;
            this.kernelSize = gaussianMaskSize;
            this.sigma = sigmaforGaussianKernel;
            this.obj = input;
            this.width1 = this.obj.Width;
            this.height1 = this.obj.Height;

            this.edgeMap = new int[this.width1, this.height1];
            this.visitedMap = new int[this.width1, this.height1];

            this.ReadImage();
            this.DetectCannyEdges();
            return;
        }

        /// <summary>
        /// Gets or sets the filtered image.
        /// </summary>
        /// <value>
        /// The filtered image.
        /// </value>
        public int[,] FilteredImage
        {
            get { return this.filteredImage; }
            set { this.filteredImage = value; }
        }

        /// <summary>
        /// Gets or sets the non max1.
        /// </summary>
        /// <value>
        /// The non max1.
        /// </value>
        public float[,] NonMax1
        {
            get { return this.nonMax; }
            set { this.nonMax = value; }
        }

        /// <summary>
        /// Gets or sets the post hysteresis.
        /// </summary>
        /// <value>
        /// The post hysteresis.
        /// </value>
        public int[,] PostHysteresis
        {
            get { return this.postHysteresis; }
            set { this.postHysteresis = value; }
        }

        /// <summary>
        /// Gets or sets the edge points.
        /// </summary>
        /// <value>
        /// The edge points.
        /// </value>
        public int[,] EdgePoints
        {
            get { return this.edgePoints; }
            set { this.edgePoints = value; }
        }

        /// <summary>
        /// Gets or sets the GNH.
        /// </summary>
        /// <value>
        /// The GNH.
        /// </value>
        public float[,] GNH
        {
            get { return this.gNH; }
            set { this.gNH = value; }
        }

        /// <summary>
        /// Gets or sets the GNL.
        /// </summary>
        /// <value>
        /// The GNL.
        /// </value>
        public float[,] GNL
        {
            get { return this.gNL; }
            set { this.gNL = value; }
        }

        /// <summary>
        /// Gets or sets the edge map.
        /// </summary>
        /// <value>
        /// The edge map.
        /// </value>
        public int[,] EdgeMap
        {
            get { return this.edgeMap; }
            set { this.edgeMap = value; }
        }

        /// <summary>
        /// Gets or sets the visited map.
        /// </summary>
        /// <value>
        /// The visited map.
        /// </value>
        public int[,] VisitedMap
        {
            get { return this.visitedMap; }
            set { this.visitedMap = value; }
        }

        /// <summary>
        /// Gets or sets the width.
        /// </summary>
        /// <value>
        /// The width.
        /// </value>
        public int Width { get; set; }

        /// <summary>
        /// Gets or sets the height.
        /// </summary>
        /// <value>
        /// The height.
        /// </value>
        public int Height { get; set; }

        /// <summary>
        /// Displays the image.
        /// </summary>
        /// <returns>Bitmap image</returns>
        public Bitmap DisplayImage()
        {
            int i, j;
            Bitmap image = new Bitmap(this.obj.Width, this.obj.Height);
            BitmapData bitmapData1 = image.LockBits(new Rectangle(0, 0, this.obj.Width, this.obj.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            unsafe
            {
                byte* imagePointer1 = (byte*)bitmapData1.Scan0;

                for (i = 0; i < bitmapData1.Height; i++)
                {
                    for (j = 0; j < bitmapData1.Width; j++)
                    {
                        // write the logic implementation here
                        imagePointer1[0] = (byte)this.greyImage[j, i];
                        imagePointer1[1] = (byte)this.greyImage[j, i];
                        imagePointer1[2] = (byte)this.greyImage[j, i];
                        imagePointer1[3] = (byte)255; 

                        // 4 bytes per pixel
                        imagePointer1 += 4;
                    } // end for j

                    // 4 bytes per pixel
                    imagePointer1 += bitmapData1.Stride - (bitmapData1.Width * 4);
                } // end for i
            } // end unsafe
            image.UnlockBits(bitmapData1);
            return image; // col;
        }

        /// <summary>
        /// Displays the image.
        /// </summary>
        /// <param name="greyImage">The grey image.</param>
        /// <returns>bitmap image</returns>
        public Bitmap DisplayImage(float[,] greyImage)
        {
            int i, j;
            int w, h;
            w = greyImage.GetLength(0);
            h = greyImage.GetLength(1);
            Bitmap image = new Bitmap(w, h);
            BitmapData bitmapData1 = image.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            unsafe
            {
                byte* imagePointer1 = (byte*)bitmapData1.Scan0;

                for (i = 0; i < bitmapData1.Height; i++)
                {
                    for (j = 0; j < bitmapData1.Width; j++)
                    {
                        // write the logic implementation here
                        imagePointer1[0] = (byte)((int)greyImage[j, i]);
                        imagePointer1[1] = (byte)((int)greyImage[j, i]);
                        imagePointer1[2] = (byte)((int)greyImage[j, i]);
                        imagePointer1[3] = (byte)255; 

                        // 4 bytes per pixel
                        imagePointer1 += 4;
                    }  

                    // 4 bytes per pixel
                    imagePointer1 += bitmapData1.Stride - (bitmapData1.Width * 4);
                } // End for i
            } // end unsafe

            image.UnlockBits(bitmapData1);
            return image; // col;
        }

        /// <summary>
        /// Displays the image.
        /// </summary>
        /// <param name="greyImage">The grey image.</param>
        /// <returns>Bitmap image</returns>
        public Bitmap DisplayImage(int[,] greyImage)
        {
            int i, j;
            int w, h;
            w = greyImage.GetLength(0);
            h = greyImage.GetLength(1);
            Bitmap image = new Bitmap(w, h);
            BitmapData bitmapData1 = image.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            unsafe
            {
                byte* imagePointer1 = (byte*)bitmapData1.Scan0;

                for (i = 0; i < bitmapData1.Height; i++)
                {
                    for (j = 0; j < bitmapData1.Width; j++)
                    {
                        // write the logic implementation here
                        imagePointer1[0] = (byte)greyImage[j, i];
                        imagePointer1[1] = (byte)greyImage[j, i];
                        imagePointer1[2] = (byte)greyImage[j, i];
                        imagePointer1[3] = (byte)255;

                        // 4 bytes per pixel
                        imagePointer1 += 4;
                    }   

                    // 4 bytes per pixel
                    imagePointer1 += bitmapData1.Stride - (bitmapData1.Width * 4);
                }
            }

            image.UnlockBits(bitmapData1);
            return image; // col
        }      

        /// <summary>
        /// Displays the image.
        /// </summary>
        /// <param name="greyImage">The grey image.</param>
        /// <returns>Imagestructure for canny image</returns>
        public ImageStructure[,] ReturnImageStructure(int[,] greyImage)
        {
            int height = greyImage.GetLength(0);
            int width = greyImage.GetLength(1);
            ImageStructure[,] img = new ImageStructure[height, width];
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    img[i, j].R = (byte)greyImage[i, j];
                    img[i, j].G = (byte)greyImage[i, j];
                    img[i, j].B = (byte)greyImage[i, j];
                }
            }

            return img;
        }

        /// <summary>
        /// Reads the image.
        /// </summary>
        private void ReadImage()
        {
            int i, j;
            this.greyImage = new int[this.obj.Width, this.obj.Height];  // [Row,Column]
            Bitmap image = this.obj;
            BitmapData bitmapData1 = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            unsafe
            {
                byte* imagePointer1 = (byte*)bitmapData1.Scan0;

                for (i = 0; i < bitmapData1.Height; i++)
                {
                    for (j = 0; j < bitmapData1.Width; j++)
                    {
                        this.greyImage[j, i] = (int)((imagePointer1[0] + imagePointer1[1] + imagePointer1[2]) / 3.0);

                        // 4 bytes per pixel
                        imagePointer1 += 4;
                    } // end for j

                    // 4 bytes per pixel
                    imagePointer1 += bitmapData1.Stride - (bitmapData1.Width * 4);
                } // end for i
            } // end unsafe
            image.UnlockBits(bitmapData1);
            return;
        }

        /// <summary>
        /// Generates the gaussian kernel.
        /// </summary>
        /// <param name="n">The N.</param>
        /// <param name="s">The S.</param>
        /// <param name="weight">The weight.</param>
        private void GenerateGaussianKernel(int n, float s, out int weight)
        {
            float sigma = s;
            float pi;
            pi = (float)Math.PI;
            int i, j;
            int sizeofKernel = n;

            float[,] kernel = new float[n, n];
            this.gaussianKernel = new int[n, n];
            float[,] oP = new float[n, n];
            float d1, d2;

            d1 = 1 / (2 * pi * sigma * sigma);
            d2 = 2 * sigma * sigma;
            float min = 1000;

            for (i = -sizeofKernel / 2; i <= sizeofKernel / 2; i++)
            {
                for (j = -sizeofKernel / 2; j <= sizeofKernel / 2; j++)
                {
                    kernel[((sizeofKernel / 2) + i), ((sizeofKernel / 2) + j)] = (1 / d1) * (float)Math.Exp(-((i * i) + (j * j)) / d2);
                    if (kernel[((sizeofKernel / 2) + i), ((sizeofKernel / 2) + j)] < min)
                    {
                        min = kernel[((sizeofKernel / 2) + i), ((sizeofKernel / 2) + j)];
                    }
                }
            }

            int mult = (int)(1 / min);
            int sum = 0;
            if ((min > 0) && (min < 1))
            {
                for (i = -sizeofKernel / 2; i <= sizeofKernel / 2; i++)
                {
                    for (j = -sizeofKernel / 2; j <= sizeofKernel / 2; j++)
                    {
                        kernel[(sizeofKernel / 2) + i, (sizeofKernel / 2) + j] = (float)Math.Round(kernel[(sizeofKernel / 2) + i, (sizeofKernel / 2) + j] * mult, 0);
                        this.gaussianKernel[(sizeofKernel / 2) + i, (sizeofKernel / 2) + j] = (int)kernel[(sizeofKernel / 2) + i, (sizeofKernel / 2) + j];
                        sum = sum + this.gaussianKernel[(sizeofKernel / 2) + i, (sizeofKernel / 2) + j];
                    }
                }
            }
            else
            {
                sum = 0;
                for (i = -sizeofKernel / 2; i <= sizeofKernel / 2; i++)
                {
                    for (j = -sizeofKernel / 2; j <= sizeofKernel / 2; j++)
                    {
                        kernel[(sizeofKernel / 2) + i, (sizeofKernel / 2) + j] = (float)Math.Round(kernel[(sizeofKernel / 2) + i, (sizeofKernel / 2) + j], 0);
                        this.gaussianKernel[(sizeofKernel / 2) + i, (sizeofKernel / 2) + j] = (int)kernel[(sizeofKernel / 2) + i, (sizeofKernel / 2) + j];
                        sum = sum + this.gaussianKernel[(sizeofKernel / 2) + i, (sizeofKernel / 2) + j];
                    }
                }
            }

            // Normalizing kernel Weight
            weight = sum;

            return;
        }

        /// <summary>
        /// Gaussians the filter.
        /// </summary>
        /// <param name="data">The data.</param>
        /// <returns>int array image</returns>
        private int[,] GaussianFilter(int[,] data)
        {
            this.GenerateGaussianKernel(this.kernelSize, this.sigma, out this.kernelWeight);
            int[,] output = new int[this.Width, this.Height];
            int i, j, k, l;
            int limit = this.kernelSize / 2;
            float sum = 0;
            output = data; // Removes Unwanted Data Omission due to kernel bias while convolution

            for (i = limit; i <= ((this.width1 - 1) - limit); i++)
            {
                for (j = limit; j <= ((this.height1 - 1) - limit); j++)
                {
                    sum = 0;
                    for (k = -limit; k <= limit; k++)
                    {
                        for (l = -limit; l <= limit; l++)
                        {
                            sum = sum + ((float)data[i + k, j + l] * this.gaussianKernel[limit + k, limit + l]);
                        }
                    }

                    output[i, j] = (int)Math.Round(sum / (float)this.kernelWeight);
                }
            }

            return output;
        }

        /// <summary>
        /// Differentiates the specified data.
        /// </summary>
        /// <param name="data">The data.</param>
        /// <param name="filter">The filter.</param>
        /// <returns>float array image</returns>
        private float[,] Differentiate(int[,] data, int[,] filter)
        {
            int i, j, k, l, fh, fw;

            fw = filter.GetLength(0);
            fh = filter.GetLength(1);
            float sum = 0;
            float[,] output = new float[this.width1, this.height1];

            for (i = fw / 2; i <= (this.width1 - (fw / 2)) - 1; i++)
            {
                for (j = fh / 2; j <= (this.height1 - (fh / 2)) - 1; j++)
                {
                    sum = 0;
                    for (k = -fw / 2; k <= (fw / 2); k++)
                    {
                        for (l = -fh / 2; l <= (fh / 2); l++)
                        {
                            sum = sum + (data[(i + k), (j + l)] * filter[((fw / 2) + k), ((fh / 2) + l)]);
                        }
                    }

                    output[i, j] = sum;
                }
            }

            return output;
        }

        /// <summary>
        /// Detects the canny edges.
        /// </summary>
        private void DetectCannyEdges()
        {
            this.gradient = new float[this.width1, this.height1];
            this.nonMax = new float[this.width1, this.height1];
            this.postHysteresis = new int[this.width1, this.height1];

            this.derivativeX = new float[this.width1, this.height1];
            this.derivativeY = new float[this.width1, this.height1];

            // Gaussian Filter Input Image 
            this.filteredImage = this.GaussianFilter(this.greyImage);

            // Sobel Masks
            int[,] dx = { { 1, 0, -1 }, { 1, 0, -1 }, { 1, 0, -1 } };

            int[,] dy = { { 1, 1, 1 }, { 0, 0, 0 }, { -1, -1, -1 } };
            this.derivativeX = this.Differentiate(this.filteredImage, dx);
            this.derivativeY = this.Differentiate(this.filteredImage, dy);
            int i, j;

            // Compute the gradient magnitude based on derivatives in x and y:
            for (i = 0; i <= (this.width1 - 1); i++)
            {
                for (j = 0; j <= (this.height1 - 1); j++)
                {
                    this.gradient[i, j] = (float)Math.Sqrt((this.derivativeX[i, j] * this.derivativeX[i, j]) + (this.derivativeY[i, j] * this.derivativeY[i, j]));
                }
            }

            // Perform Non maximum suppression:
            // NonMax = Gradient;
            for (i = 0; i <= (this.width1 - 1); i++)
            {
                for (j = 0; j <= (this.height1 - 1); j++)
                {
                    this.nonMax[i, j] = this.gradient[i, j];
                }
            }

            int limit = this.kernelSize / 2;
            int r, c;
            float tangent;
            for (i = limit; i <= (this.width1 - limit) - 1; i++)
            {
                for (j = limit; j <= (this.height1 - limit) - 1; j++)
                {
                    if (this.derivativeX[i, j] == 0)
                    {
                        tangent = 90F;
                    }
                    else
                    {
                        tangent = (float)(Math.Atan(this.derivativeY[i, j] / this.derivativeX[i, j]) * 180 / Math.PI); // rad to degree
                    }

                    // Horizontal Edge
                    if (((-22.5 < tangent) && (tangent <= 22.5)) || ((157.5 < tangent) && (tangent <= -157.5)))
                    {
                        if ((this.gradient[i, j] < this.gradient[i, j + 1]) || (this.gradient[i, j] < this.gradient[i, j - 1]))
                        {
                            this.nonMax[i, j] = 0; 
                        }
                    }

                    // Vertical Edge
                    if (((-112.5 < tangent) && (tangent <= -67.5)) || ((67.5 < tangent) && (tangent <= 112.5)))
                    {
                        if ((this.gradient[i, j] < this.gradient[i + 1, j]) || (this.gradient[i, j] < this.gradient[i - 1, j]))
                        {
                            this.nonMax[i, j] = 0;
                        }
                    }

                    // +45 Degree Edge
                    if (((-67.5 < tangent) && (tangent <= -22.5)) || ((112.5 < tangent) && (tangent <= 157.5)))
                    {
                        if ((this.gradient[i, j] < this.gradient[i + 1, j - 1]) || (this.gradient[i, j] < this.gradient[i - 1, j + 1]))
                        {
                            this.nonMax[i, j] = 0;
                        }
                    }

                    // -45 Degree Edge
                    if (((-157.5 < tangent) && (tangent <= -112.5)) || ((67.5 < tangent) && (tangent <= 22.5)))
                    {
                        if ((this.gradient[i, j] < this.gradient[i + 1, j + 1]) || (this.gradient[i, j] < this.gradient[i - 1, j - 1]))
                        {
                            this.nonMax[i, j] = 0;
                        }
                    }
                }
            }

            // PostHysteresis = NonMax;
            for (r = limit; r <= (this.width1 - limit) - 1; r++)
            {
                for (c = limit; c <= (this.height1 - limit) - 1; c++)
                {
                    this.postHysteresis[r, c] = (int)this.nonMax[r, c];
                }
            }

            // Find Max and Min in Post Hysterisis
            float min, max;
            min = 100;
            max = 0;
            for (r = limit; r <= (this.width1 - limit) - 1; r++)
            {
                for (c = limit; c <= (this.height1 - limit) - 1; c++)
                {
                    if (this.postHysteresis[r, c] > max)
                    {
                        max = this.postHysteresis[r, c];
                    }

                    if ((this.postHysteresis[r, c] < min) && (this.postHysteresis[r, c] > 0))
                    {
                        min = this.postHysteresis[r, c];
                    }
                }
            }

            this.gNH = new float[this.width1, this.height1];
            this.gNL = new float[this.width1, this.height1];
            this.edgePoints = new int[this.width1, this.height1];

            for (r = limit; r <= (this.width1 - limit) - 1; r++)
            {
                for (c = limit; c <= (this.height1 - limit) - 1; c++)
                {
                    if (this.postHysteresis[r, c] >= this.maxHysteresisThresh)
                    {
                        this.edgePoints[r, c] = 1;
                        this.gNH[r, c] = 255;
                    }

                    if ((this.postHysteresis[r, c] < this.maxHysteresisThresh) && (this.postHysteresis[r, c] >= this.minHysteresisThresh))
                    {
                        this.edgePoints[r, c] = 2;
                        this.gNL[r, c] = 255;
                    }
                }
            }

            this.HysterisisThresholding(this.edgePoints);
            for (i = 0; i <= (this.width1 - 1); i++)
            {
                for (j = 0; j <= (this.height1 - 1); j++)
                {
                    this.edgeMap[i, j] = this.edgeMap[i, j] * 255;
                }
            }

            return;
        }

        /// <summary>
        /// Hysterisises the thresholding.
        /// </summary>
        /// <param name="edges">The edges.</param>
        private void HysterisisThresholding(int[,] edges)
        {
            int i, j;
            int limit = this.kernelSize / 2;

            for (i = limit; i <= (this.width1 - 1) - limit; i++)
            {
                for (j = limit; j <= (this.height1 - 1) - limit; j++)
                {
                    if (edges[i, j] == 1)
                    {
                        this.edgeMap[i, j] = 1;
                    }
                }
            }

            for (i = limit; i <= (this.width1 - 1) - limit; i++)
            {
                for (j = limit; j <= (this.height1 - 1) - limit; j++)
                {
                    if (edges[i, j] == 1)
                    {
                        this.edgeMap[i, j] = 1;
                        this.Travers(i, j);
                        this.visitedMap[i, j] = 1;
                    }
                }
            }

            return;
        }

        /// <summary>
        /// Traverses the specified X.
        /// </summary>
        /// <param name="x">The X.</param>
        /// <param name="y">The Y.</param>
        private void Travers(int x, int y)
        {
            if (this.visitedMap[x, y] == 1)
            {
                return;
            }

            // 1
            if (this.edgePoints[x + 1, y] == 2)
            {
                this.edgeMap[x + 1, y] = 1;
                this.visitedMap[x + 1, y] = 1;
                this.Travers(x + 1, y);
                return;
            }

            // 2
            if (this.edgePoints[x + 1, y - 1] == 2)
            {
                this.edgeMap[x + 1, y - 1] = 1;
                this.visitedMap[x + 1, y - 1] = 1;
                this.Travers(x + 1, y - 1);
                return;
            }

            // 3
            if (this.edgePoints[x, y - 1] == 2)
            {
                this.edgeMap[x, y - 1] = 1;
                this.visitedMap[x, y - 1] = 1;
                this.Travers(x, y - 1);
                return;
            }

            // 4
            if (this.edgePoints[x - 1, y - 1] == 2)
            {
                this.edgeMap[x - 1, y - 1] = 1;
                this.visitedMap[x - 1, y - 1] = 1;
                this.Travers(x - 1, y - 1);
                return;
            }

            // 5
            if (this.edgePoints[x - 1, y] == 2)
            {
                this.edgeMap[x - 1, y] = 1;
                this.visitedMap[x - 1, y] = 1;
                this.Travers(x - 1, y);
                return;
            } 

            // 6
            if (this.edgePoints[x - 1, y + 1] == 2)
            {
                this.edgeMap[x - 1, y + 1] = 1;
                this.visitedMap[x - 1, y + 1] = 1;
                this.Travers(x - 1, y + 1);
                return;
            }

            // 7
            if (this.edgePoints[x, y + 1] == 2)
            {
                this.edgeMap[x, y + 1] = 1;
                this.visitedMap[x, y + 1] = 1;
                this.Travers(x, y + 1);
                return;
            } 

            // 8
            if (this.edgePoints[x + 1, y + 1] == 2)
            {
                this.edgeMap[x + 1, y + 1] = 1;
                this.visitedMap[x + 1, y + 1] = 1;
                this.Travers(x + 1, y + 1);
                return;
            }

            // VisitedMap[X, Y] = 1;
            return;
        }
    }
}
